package vn.vfriends.vcms.admin.bean;

import eu.medsea.mimeutil.MimeUtil2;
import java.io.File;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.omnifaces.util.Faces;
import org.primefaces.context.RequestContext;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.event.NodeSelectEvent;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.StreamedContent;
import org.primefaces.model.TreeNode;
import org.primefaces.model.UploadedFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author tuan@vfriends.vn
 */
@Named
@ConversationScoped
public class FileManagerBean implements Serializable {
    private static final Logger logger = LoggerFactory.getLogger(FileManagerBean.class);
    
    @Inject private Conversation conversation;
    
    private TreeNode root;
    
    private TreeNode selectedNode;

    private StreamedContent downloadStreamContent;
    
    private String newName;
    
    private String newPath;
    
    private String newFileType;
    
    static private final String ROOT_PATH = Faces.getInitParameter("ROOT_PATH");
    
    @PostConstruct
    public void init(){
        if (conversation.isTransient()) {
            conversation.begin();
        }
    }
    
    public FileManagerBean() {
        try {
            this.initRoot();
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }
    
    private void initRoot() throws Exception {
        root = new DefaultTreeNode("root", null);
        
        File rootFile = new File(ROOT_PATH);
        if(!rootFile.exists()) {
            FileUtils.forceMkdir(rootFile);
        }
        File[] children = rootFile.listFiles();
        for (File child : children) {
            this.initNode(root, child);
        }
    }
    
    public TreeNode getRoot() {
        return root;
    }
    
    private void initNode(TreeNode node, File file) throws Exception {
        if(file.isDirectory()) {
            TreeNode child = new DefaultTreeNode(file, node);
            File[] children = file.listFiles();
            for (File childFile : children) {
                this.initNode(child, childFile);
            }
        } else {
            TreeNode child = new DefaultTreeNode("document", file, node);
        }
    }

    public Conversation getConversation() {
        return conversation;
    }

    public StreamedContent getDownloadStreamContent() {
        return downloadStreamContent;
    }

    public TreeNode getSelectedNode() {
        return selectedNode;
    }

    public void setSelectedNode(TreeNode selectedNode) {
        this.selectedNode = selectedNode;
    }

    public String getNewName() {
        return newName;
    }

    public void setNewName(String newName) {
        this.newName = newName;
    }

    public String getNewPath() {
        return newPath;
    }

    public void setNewPath(String newPath) {
        this.newPath = newPath;
    }

    public String getNewFileType() {
        return newFileType;
    }

    public void setNewFileType(String newFileType) {
        this.newFileType = newFileType;
    }

    public void createAction() {
        File selectedFile = null;
        if (this.selectedNode == null) {
            selectedFile = new File(ROOT_PATH);
        } else {
            selectedFile = (File) this.selectedNode.getData();
        }
        try {
            if (selectedFile.isFile()) {
                String parentPath = selectedFile.getCanonicalPath();
                selectedFile = new File(parentPath);
            }

            File newFile = new File(FilenameUtils.concat(selectedFile.getAbsolutePath(), newName));
            if (this.newFileType.equals("File")) {
                newFile.createNewFile();
            } else {
                FileUtils.forceMkdir(newFile);
            }
            this.initRoot();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), ""));
        } finally {
            this.newName = "";
            this.newFileType = "";
        }
    }
    
    public void preRenameAction() {
        if(this.selectedNode == null) {
            RequestContext.getCurrentInstance().addCallbackParam("invalid", true);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Hãy chọn file hoặc thư mục", ""));
        } else {
            File selectedFile = (File)this.selectedNode.getData();
            this.newName = selectedFile.getName();
        }
    }
    
    public void renameAction() {
        if(this.selectedNode == null) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Hãy chọn file hoặc thư mục", ""));
        } else {
            File oldFile = (File)this.selectedNode.getData();
            if(oldFile.getName().equals(this.newName)) {
                return;
            }
            
            try {
                String path = FilenameUtils.getFullPath(oldFile.getAbsolutePath());
                File newFile = new File(FilenameUtils.concat(path, newName));
                oldFile.renameTo(newFile);

                this.initRoot();
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), ""));
            } finally {
                this.newName = "";
            }
        }
    }
    
    public void preMoveAction() {
        if(this.selectedNode == null) {
            RequestContext.getCurrentInstance().addCallbackParam("invalid", true);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Hãy chọn file hoặc thư mục", ""));
        } else {
            File selectedFile = (File)this.selectedNode.getData();
            this.newPath = StringUtils.substringAfter(selectedFile.getAbsolutePath(), ROOT_PATH + "/");
        }
    }
    
    public void moveAction() {
        File selectedFile = (File) this.selectedNode.getData();
        if (selectedFile.getPath().equals(this.newPath)) {
            return;
        }

        try {
            File destFile = new File(FilenameUtils.concat(ROOT_PATH, newPath));
            if (selectedFile.isDirectory()) {
                FileUtils.moveDirectory(selectedFile, destFile);
            } else {
                FileUtils.moveFile(selectedFile, destFile);
            }
            selectedFile.delete();
            this.initRoot();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), ""));
        } finally {
            this.newPath = "";
        }
    }
    
    public void preCopyAction() {
        if(this.selectedNode == null) {
            RequestContext.getCurrentInstance().addCallbackParam("invalid", true);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Hãy chọn file hoặc thư mục", ""));
        } else {
            File selectedFile = (File)this.selectedNode.getData();
            this.newPath = StringUtils.substringAfter(selectedFile.getAbsolutePath(), ROOT_PATH + "/");
        }
    }
    
    public void copyAction() {
        File selectedFile = (File) this.selectedNode.getData();
        if (selectedFile.getPath().equals(this.newPath)) {
            return;
        }

        try {
            File destFile = new File(FilenameUtils.concat(ROOT_PATH, newPath));
            if (selectedFile.isDirectory()) {
                FileUtils.copyDirectory(selectedFile, destFile);
            } else {
                FileUtils.copyFile(selectedFile, destFile);
            }

            this.initRoot();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), ""));
        } finally {
            this.newPath = "";
        }
    }
    
    public void preDeleteAction() {
        if(this.selectedNode == null) {
            RequestContext.getCurrentInstance().addCallbackParam("invalid", true);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Hãy chọn file hoặc thư mục", ""));
        }
    }
    
    public void deleteAction() {
        if(this.selectedNode == null) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Hãy chọn file hoặc thư mục", ""));
        } else {
            File file = (File)this.selectedNode.getData();
            try {
                if(file.exists()) {
                    file.delete();
                }

                this.initRoot();
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), ""));
            }
        }
    }
    
    public void reloadAction() {
        try {
            this.initRoot();
        } catch(Exception e) {
            logger.error(e.getMessage(), e);
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), ""));
        }
    }
    
    public void onNodeSelectAction(NodeSelectEvent event) {
        File selectedDirectory = (File)event.getTreeNode().getData();
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Selected " + selectedDirectory.getName(), "");
        FacesContext.getCurrentInstance().addMessage(null, message);
    }
    
    public void uploadFileAction(FileUploadEvent event) {
        try {
            File selectedFile = null;
            if (this.selectedNode == null) {
                selectedFile = new File(ROOT_PATH);
            } else {
                selectedFile = (File)this.selectedNode.getData();
            }
            
            UploadedFile uploadedFile = event.getFile();
            String path = FilenameUtils.concat(selectedFile.getAbsolutePath(), uploadedFile.getFileName());
            File file = new File(path);
            FileUtils.writeByteArrayToFile(file, uploadedFile.getContents());
            
            this.initRoot();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), ""));
        }
    }
    
    public void preGetDownloadLinkAction() {
        if(this.selectedNode == null) {
            RequestContext.getCurrentInstance().addCallbackParam("invalid", true);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Hãy chọn một file", ""));
        } else {
            File selectedFile = (File)this.selectedNode.getData();
            if(selectedFile.isDirectory()) {
                RequestContext.getCurrentInstance().addCallbackParam("invalid", true);
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Hãy chọn một file", ""));
            }
        }
    }
    
    public String getDownloadLink() {
        if(this.selectedNode == null) {
            return "";
        }
        File selectedFile = (File)this.selectedNode.getData();
        String path = selectedFile.getAbsolutePath();
        path = StringUtils.substringAfter(path, ROOT_PATH + "/");
        try {
            String url = Faces.getInitParameter("DOWNLOAD_BASE_URL")
                    + "file?p="
                    + URLEncoder.encode(path, "UTF-8");
            return url;
        } catch (UnsupportedEncodingException ex) {
            logger.error(ex.getMessage());
        }
        return "";
    }
    
    private String getMimeType(File file) {
        MimeUtil2 mimeUtil = new MimeUtil2();
        mimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
        return MimeUtil2.getMostSpecificMimeType(mimeUtil.getMimeTypes(file)).toString();
    }
    
    public Date getLastModified(File file) {
        return new Date(file.lastModified());
    }
}
